package com.jfs.config;

import com.jfs.constant.SipConstant;
import com.jfs.observer.SIPProcessorObserver;
import com.jfs.properties.SipProperties;
import gov.nist.javax.sip.SipProviderImpl;
import lombok.extern.slf4j.Slf4j;
import org.springframework.boot.context.properties.EnableConfigurationProperties;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;

import javax.sip.*;
import java.util.Properties;
import java.util.TooManyListenersException;

/**
 * @Description sip信令服务器配置类
 * @E-mail cwm3412638@163.com
 * @Author cwm
 * @Date 2022-08-23
 */
@Configuration
@Slf4j
@EnableConfigurationProperties(value = SipProperties.class)
public class SipServerConfig {
    /**
     * 配置sip协议栈创建广场Bean
     *
     * @return
     */
    @Bean
    SipFactory sipFactory() {
        SipFactory sipFactory = SipFactory.getInstance();
        sipFactory.setPathName(SipConstant.SIP_PATH_NAME);
        return sipFactory;
    }


    @Bean
    SipStack sipStack(SipProperties sipProperties) throws PeerUnavailableException {
        /**
         * 完整配置参考 gov.nist.javax.sip.SipStackImpl，需要下载源码
         * gov/nist/javax/sip/SipStackImpl.class
         */
        Properties properties = new Properties();
        //设置栈名称
        properties.setProperty(SipConstant.SIP_STACK_NAME_KEY, SipConstant.SIP_STACK_NAME_VALUE);
        //设置栈ip
        properties.setProperty(SipConstant.SIP_IP_ADDRESS_KEY, sipProperties.getMonitorIp());
        //设置日志
        properties.setProperty(SipConstant.SIP_LOG_MESSAGE_CONTENT_KEY, String.valueOf(Boolean.TRUE));
        //接收所有notify请求，即使没有订阅
        properties.setProperty(SipConstant.DELIVER_UNSOLICITED_NOTIFY_KEY, String.valueOf(Boolean.TRUE));
        //为NULL 对话框传递终止的事件
        properties.setProperty(SipConstant.DELIVER_TERMINATED_EVENT_FOR_NULL_DIALOG_KEY, String.valueOf(Boolean.TRUE));
        //会话清理策略
        properties.setProperty(SipConstant.RELEASE_REFERENCES_STRATEGY_KEY, SipConstant.RELEASE_REFERENCES_STRATEGY_VALUE);
        //心跳超时时间
        properties.setProperty(SipConstant.RELIABLE_CONNECTION_KEEP_ALIVE_TIMEOUT_KEY, String.valueOf(sipProperties.getKeepaliveTimeOut()));
        /** 解决 481 Subscription does not exist */
        // properties.setProperty(SipConstant.AUTOMATIC_DIALOG_SUPPORT_KEY, SipConstant.AUTOMATIC_DIALOG_SUPPORT_VALUE);
        return sipFactory().createSipStack(properties);
    }

    /**
     * 配置tcp sip
     *
     * @param sipProperties
     * @param sipProcessorObserver
     * @return
     * @throws PeerUnavailableException
     * @throws TransportNotSupportedException
     * @throws InvalidArgumentException
     * @throws ObjectInUseException
     */
    @Bean
    SipProvider tcpSipProvider(SipProperties sipProperties, SIPProcessorObserver sipProcessorObserver) throws PeerUnavailableException, TransportNotSupportedException, InvalidArgumentException, ObjectInUseException, TooManyListenersException {
        //设置监听地址和端口
        ListeningPoint tcpListeningPoint = sipStack(sipProperties).createListeningPoint(sipProperties.getMonitorIp(), sipProperties.getPort(), SipConstant.TRANSPORT_TCP);
        SipProviderImpl tcpSipProvider = (SipProviderImpl) sipStack(sipProperties).createSipProvider(tcpListeningPoint);
        log.info("【TCP SIP SERVER START，MONITOR PORT:【{}】", sipProperties.getPort());
        tcpSipProvider.setDialogErrorsAutomaticallyHandled();
        tcpSipProvider.addSipListener(sipProcessorObserver);
        return tcpSipProvider;
    }

    /**
     * 配置udp sip
     *
     * @param sipProperties
     * @param sipProcessorObserver
     * @return
     * @throws TransportNotSupportedException
     * @throws InvalidArgumentException
     * @throws ObjectInUseException
     * @throws TooManyListenersException
     * @throws PeerUnavailableException
     */
    @Bean
    SipProviderImpl udpSipProvider(SipProperties sipProperties, SIPProcessorObserver sipProcessorObserver) throws TransportNotSupportedException, InvalidArgumentException, ObjectInUseException, TooManyListenersException, PeerUnavailableException {
        ListeningPoint udpListeningPoint = sipStack(sipProperties).createListeningPoint(sipProperties.getMonitorIp(), sipProperties.getPort(), SipConstant.TRANSPORT_UDP);
        SipProviderImpl udpSipProvider = (SipProviderImpl) sipStack(sipProperties).createSipProvider(udpListeningPoint);
        log.info("【UDP SIP SERVER START，MONITOR PORT:【{}】", sipProperties.getPort());
        udpSipProvider.addSipListener(sipProcessorObserver);
        return udpSipProvider;
    }
}
